//
// Created by hjie on 23-6-22.
//

#include "connection_data_room.h"
#include "room_manager.h"
#include "logic/logic_room_data.h"
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include "protocol/msg_key.h"
#include "logic/message_router.h"
#include "data/data_define.h"

ConnectionDataRoom::ConnectionDataRoom(RoomManager *room_manager, const std::string & room_id)
{
    m_room_manager = room_manager;
    m_room_id      = room_id;
    m_data_manager = std::make_shared<DataManager>(this);
    m_last_recv_msg_time = time(nullptr);
}

ConnectionDataRoom::~ConnectionDataRoom()
{
    m_room_thread_msg_queue->UnReference();
    m_connection_data_map.clear();
    m_room_thread_msg_queue = nullptr;
    printf("~ConnectionDataRoom room_id : %s.\n", m_room_id.c_str());
    m_room_id.clear();
}

void ConnectionDataRoom::OnTimer()
{
    uint64_t now_time = time(nullptr);
    for (auto & connection : m_connection_data_map)
    {
        if ((now_time - connection.second->m_heart_time) >= 60)
        {
            connection.second->Destroy();
        }
        else if ((now_time - connection.second->m_heart_time) >= 10)
        {
            connection.second->HeartBeat();
        }
    }
    printf("function : %s room %s connection size : %zu and timer count : %ld.\n",  __func__ , m_room_id.c_str(), m_connection_data_map.size(), m_timer_count);
    if (m_connection_data_map.empty() && (now_time - m_last_recv_msg_time) >= 60)
    {
        m_room_manager->PushCheckIdleRoom(shared_from_this());
    }
}


bool ConnectionDataRoom::AddConnectionData(ConnectionData *data)
{
    auto iter = m_connection_data_map.find(data->m_user_name);
    if (iter == m_connection_data_map.end())
    {
        m_connection_data_map[data->m_user_name] = data;
        m_data_manager->m_ud_mgr->AddUser(data->m_user_name);
        return true;
    }
    return false;
}

void ConnectionDataRoom::RemoveConnectionData(const std::string &user_name)
{
    m_connection_data_map.erase(user_name);
    m_data_manager->ClearAllData(user_name);
}

void ConnectionDataRoom::ProcessMessageProtocol(ConnectionData *data, rapidjson::Document &input)
{
    auto protocol_ptr = BaseProtocol::ParseHeaderData(input);
    if (protocol_ptr)
    {
        auto router = m_room_manager->GetMessageRouter();
        std::string msg_type = protocol_ptr->m_request_header->m_msg_type;

        m_last_recv_msg_time = time(nullptr);
        auto iter = router->m_message_protocol_func_map.find(msg_type);
        if (iter != router->m_message_protocol_func_map.end())
        {
            RoomReferenceData reference;
            reference.m_connection_data = data;
            reference.m_room = shared_from_this();
            reference.m_extra_message.SetArray();
            iter->second(&reference, protocol_ptr);

            PolicyMessage(&reference);
        }
    }
}

void ConnectionDataRoom::PolicyMessage(RoomReferenceData *reference)
{
    for (auto & data : reference->m_response_vec.m_vec)
    {
        rapidjson::Document output(rapidjson::kObjectType);
        if (data->m_response_header->m_room_id.empty())
        {
            data->m_response_header->m_room_id = m_room_id;
        }
        // prepay data to document
        data->Dump(output);

        rapidjson::StringBuffer s;
        rapidjson::Writer<rapidjson::StringBuffer> writer(s);
        output.Accept(writer);

        std::string content = s.GetString();
        auto policy = (POLICY)data->m_response_header->m_policy;
        switch(policy)
        {
            case RESPONSE:
            {
                if (reference->m_connection_data->m_socket && !reference->m_connection_data->m_socket->isClosed())
                {
                    reference->m_connection_data->m_socket->send(content.c_str(), content.size(), uWS::OpCode::TEXT);
                }
                break;
            }
            case BROADCAST:
            {
                for (auto & connection : m_connection_data_map)
                {
                    if (connection.second->m_socket && !connection.second->m_socket->isClosed())
                    {
                        connection.second->m_socket->send(content.c_str(), content.size(), uWS::OpCode::TEXT);
                    }
                }
                break;
            }
            case TARGET:
            {
                std::string user_id = output[header_k][to_k].GetString();
                auto user = m_connection_data_map.find(user_id);
                if (user != m_connection_data_map.end())
                {
                    if (user->second->m_socket && !user->second->m_socket->isClosed())
                    {
                        user->second->m_socket->send(content.c_str(), content.size(), uWS::OpCode::TEXT);
                    }
                }
                break;
            }
            default:
                break;
        }
    }
}





















